package com.tbit.uqbike.webmanager.util.csv.util;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.webmanager.util.LogUtil;

import java.util.*;

/**
 * @AUTHOR: wei.xing
 * @DATE: 2022-11-19 09:31
 **/
public class DateUtils {


    /**
     * 按天分割时间
     *
     * @param start
     * @param end
     * @param step
     * @return
     */
    public static List<List<Date>> splitByDay(Date start, Date end, int step) {
        List<List<Date>> result = new ArrayList<>();

        if (start.getTime() > end.getTime()) {
            throw new RuntimeException("开始时间大于结束时间");
        }
        List<DateTime> dateTimes = DateUtil.rangeToList(start, end, DateField.HOUR_OF_DAY, 24 * step);
        for (DateTime startTime : dateTimes) {
            List<Date> dateList = new ArrayList<>();
            Date endTime = DateUtil.offset(startTime, DateField.SECOND, step * 60 * 60 * 24 - 1);
            if (endTime.getTime() > end.getTime()) {
                endTime = end;
            }
            dateList.add(startTime);
            dateList.add(endTime);
            result.add(dateList);
        }
        return result;
    }

    /**
     * 按任务数动态拆分时间
     *
     * @param selectTotalCount  查询总任务数
     * @param singleQueryCount  查询阈值
     * @param startTime         开始时间
     * @param endTime           结束时间
     * @param selectWithBetween 时间区间是否使用 between and  <= => 如果当一个时间正好落在区间节点上，则会重复计算。
     * @return 时间区间
     */
    public static List<List<Date>> dynamicSplitQueryTimeByDataVolume(int selectTotalCount, int singleQueryCount,
                                                                     Date startTime, Date endTime, boolean selectWithBetween) {
        if (startTime.getTime() > endTime.getTime()) {
            throw new BaseException("开始时间大于结束时间");
        }
        List<List<Date>> dateGroupList = new ArrayList<>();
        double queryDurationSecond = com.tbit.uqbike.webmanager.util.DateUtils.getDateDiff(endTime, startTime) / 1000D;
        double maxQuery = 3600D;
        if (queryDurationSecond < maxQuery || selectTotalCount <= singleQueryCount) {
            //间隔时间小于60分钟全查 或者总量小于指定值
            dateGroupList.add(Arrays.asList(startTime, endTime));
            return dateGroupList;
        }
        //拆分任务总数 向上取整
        int selectTaskCount = (int) Math.ceil((double) selectTotalCount / singleQueryCount);
        int incrementSecond = (int) Math.ceil(queryDurationSecond / selectTaskCount);
        //动态减少查询次数 如果计算出来每次任务间隔时间 < 30 秒每次,说明任务次数过多 自动合并任务 提高原任务的3/1的量
        LogUtil.info(String.format("任务下载开始 下载总量%d,单次拆分量%d,查询时间[%s - %s],单次任务切割%d秒"
                , selectTotalCount, singleQueryCount,
                DateUtil.formatDateTime(startTime), DateUtil.formatDateTime(endTime), incrementSecond));
        int minIncrSecond = 30;
        if (incrementSecond < minIncrSecond) {
            incrementSecond += incrementSecond / 2;
            LogUtil.info("下载任务时间负载过高,自动扩容" + incrementSecond + "秒");
        }
        Date endTimePoint = null;
        for (int i = 0; i < selectTaskCount; i++) {
            List<Date> dataTimeBucked = new ArrayList<>();
            if (i == 0) {
                //第一次
                dataTimeBucked.add(DateTime.of(startTime));
                endTimePoint = com.tbit.uqbike.webmanager.util.DateUtils.addTime(DateTime.of(startTime), Calendar.SECOND, incrementSecond);
                dataTimeBucked.add(DateTime.of(endTimePoint));
                dateGroupList.add(dataTimeBucked);
            } else if (i == selectTaskCount - 1) {
                //最后一次
                dataTimeBucked.add(selectWithBetween ?
                        DateTime.of(com.tbit.uqbike.webmanager.util.DateUtils.addTime(DateTime.of(endTimePoint), Calendar.SECOND, 1)) :
                        DateTime.of(endTimePoint)
                );
                dataTimeBucked.add(DateTime.of(endTime));
                dateGroupList.add(dataTimeBucked);
            } else {
                //如果查询sql time 是 between and  那就需要在中间阶段每次加一秒
                Date endTimePointStash = com.tbit.uqbike.webmanager.util.DateUtils.addTime(DateTime.of(endTimePoint), Calendar.SECOND, incrementSecond);
                //动态减少查询次数 时间超限
                if (endTimePointStash.toInstant().compareTo(endTime.toInstant()) >= 0) {
                    dataTimeBucked.add(selectWithBetween ?
                            DateTime.of(com.tbit.uqbike.webmanager.util.DateUtils.addTime(DateTime.of(endTimePoint), Calendar.SECOND, 1)) :
                            DateTime.of(endTimePoint)
                    );
                    dataTimeBucked.add(endTime);
                    dateGroupList.add(dataTimeBucked);
                    break;
                } else {
                    dataTimeBucked.add(selectWithBetween ?
                            DateTime.of(com.tbit.uqbike.webmanager.util.DateUtils.addTime(DateTime.of(endTimePoint), Calendar.SECOND, 1)) :
                            DateTime.of(endTimePoint)
                    );
                    dataTimeBucked.add(DateTime.of(endTimePointStash));
                    dateGroupList.add(dataTimeBucked);
                    endTimePoint = endTimePointStash;
                }
            }
        }
        LogUtil.info("最终查询时间:" + dateGroupList);
        return dateGroupList;
    }


    public static void main(String[] args) {
        Date start = DateUtil.parse("2022-11-01 00:00:00");

        Date end = DateUtil.parse("2022-11-02 16:36:54");
        List<List<Date>> lists = DateUtils.splitByDay(start, end, 2);
        lists.forEach(v -> {
            System.out.println(v);
        });


//        System.out.println(start);
//        System.out.println(end);

    }


}
